
import java.util.*;
import java.sql.Timestamp;
import java.text.*;


import com.maxmind.geoip.Location;
import com.maxmind.geoip.LookupService;


	/**
	* @author Joshua Oberle.
	*/

// javac *.java -classpath maxmindgeoip.jar:mysql-connector-java-5.0.8-bin.jar     
// tar --to-stdout -zxf logs_03_12_2011.tar.gz | java -cp .:maxmindgeoip.jar LogFileReader        
public class LogLineReader{

	private TreeMap<Integer, IpUser> uidtree;
	private ArrayList<VizObj> vizlist;
	int currentUID;

	/**
	* Constructs a LogLineReader.
	*
	* LogLineReaders store their data locally until written to the database. LogLineReaders are not ment to handle
	* multiple files were UIDs overlap. Create individual LogLineReader's for every unique set of UIDs.
	*/

	LogLineReader(){
		uidtree = new TreeMap<Integer, IpUser>();
		vizlist = new ArrayList<VizObj>();
	}//LogLineReader constructor

	/**
	 * Takes in a line of text and parses it for useful information.
	 * 
	 * Data retreived from the lines of text are stored in Collections. The collections
	 * must be written to the database in order to be saved.
	 *
	 * @param line A line of text to be parsed for information.
	 */

	public void nextLine(String line){
		if(line.contains("INFO: /srv/www/htdocs/jhave/html_root/uid/")){
			currentUID = Integer.parseInt(line.substring(line.lastIndexOf('/') + 1,line.lastIndexOf(' ')));
		}else if(line.toLowerCase().contains("up front with user")){
			String date = line.substring(0,line.indexOf('M') + 1);
			int userbegin = line.indexOf("user  ") + 6;
			String username = line.substring(userbegin,line.indexOf(' ',userbegin));
			int vizbegin = line.indexOf("-- exe/") + 7;
			String vizname = line.substring(vizbegin, line.indexOf('/',vizbegin));
			vizlist.add(new VizObj(currentUID,vizname,username,date));
		}else if(line.toLowerCase().contains("up front looking for")){
			String date = line.substring(0,line.indexOf('M') + 1);
			int vizbegin = line.indexOf("-- exe/") + 7;
			String vizname = line.substring(vizbegin, line.indexOf('/',vizbegin));
			vizlist.add(new VizObj(currentUID,vizname,"no_username",date));
		}else if(line.contains("INFO: Accepted connection")){
			int uidbegin = line.indexOf("n ") + 2;
			int mUID = Integer.parseInt(line.substring(uidbegin,line.indexOf(' ', uidbegin)));
			String mIP = line.substring(line.indexOf("m ") + 2);
			uidtree.put(mUID,new IpUser(mIP,""));
		}
	}//nextLine(String)

	/**
	 * Sends information stored inside the LogLineReader to the database.
	 */

	public void writeToDatabase(){
		try{
			for(VizObj vobj : vizlist){
				LogHandler log = new LogHandler();
				
				//Get the timestamp of vizdate
				SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yy hh:mm aa");
				sdf.setLenient(false);
				//Date mydate = sdf.parse(vobj.vizdate);
				//System.out.println(vobj.vizdate.equals("1/13/11 7:48 AM"));
				//Timestamp timestamp = new Timestamp(sdf.parse(fromatedDateString(vobj.vizdate)).getTime());
				
				//System.out.println("VIZ: " + vobj.name + " " + getIP(vobj) + " " + vobj.user + " " + vobj.vizdate + " " + createTimestamp(vobj.vizdate));
				LogHandler.insertVisualization(vobj.name, getIP(vobj), vobj.user, createTimestamp(vobj.vizdate));
			}//for each VizObj in vizlist
			LookupService cl = new LookupService("GeoLiteCity.dat", LookupService.GEOIP_MEMORY_CACHE );
			for(IpUser ipu : uidtree.values()){
				Location loc = cl.getLocation(ipu.ip);
				//System.out.println("IP: " + ipu.ip + " " + ipu.user + " " + loc.region + " " + loc.city + " " + loc.countryName);
				LogHandler.insertIP(ipu.ip, ipu.user, loc.region, loc.city, loc.countryName);
	
			}//for each Ip and User in uidtree
			cl.close();
		}catch (Exception e) {
			e.printStackTrace();
		}
	}//writeToDatabase

	/**
	 * Method used to get and set the IP for the VizObj from the uidtree
	 *
	 * @param vobj The VizObj who's IP you would like to receive.
	 */

	private String getIP(VizObj vobj){
		String mIP = uidtree.get(vobj.uid).ip;
		uidtree.put(vobj.uid,new IpUser(mIP,vobj.user));
		return mIP;
	}

	private Timestamp createTimestamp(String sdate){
		Calendar calendar = Calendar.getInstance();
		int mpos = sdate.indexOf('/');
		int month = Integer.parseInt(sdate.substring(0,mpos)) - 1;
		int dpos = sdate.indexOf('/', mpos + 1);
		int day = Integer.parseInt(sdate.substring(mpos + 1, dpos)) - 1;
		int ypos = sdate.indexOf(' ', dpos + 1);
		int year = Integer.parseInt(sdate.substring(dpos + 1, ypos)) + 2000;
		int hpos = sdate.indexOf(':', ypos + 1);
		int hour = Integer.parseInt(sdate.substring(ypos + 1, hpos));
		int mipos = sdate.indexOf(' ', hpos + 1);
		int min = Integer.parseInt(sdate.substring(hpos + 1, mipos));
		int ampm = 0;
		if( sdate.charAt(mipos + 1) == 'P')
			ampm = 12;
		if(hour == 12){
			if(ampm == 12)
				ampm = 0;
			else
				ampm = 12;
		}
		calendar.set(year,month,day,hour+ampm,min);
		calendar.set(Calendar.SECOND, 0);
		calendar.set(Calendar.MILLISECOND, 0);
		return new Timestamp(calendar.getTimeInMillis());
	}

}//LogLineReader class

	/**
	 * A tuple to store IP and User.
	 * @author Joshua Oberle
	 */

class IpUser{
	public String ip;
	public String user;

	/**
	 * Constructor that stores the data in the tuple.
	 * @param ip The IP you wish to store.
	 * @param user A string representing the user you would like to store.
	 */

	IpUser(String ip, String user){
		this.ip = ip;
		this.user = user;
	}//IpUser(String, String) constructor

}//IpUser class

	/**
	 * Stores information about a vizulation.
	 * @author Joshua Oberle
	 */

class VizObj{
	public int uid;
	public String name;
	public String user;
	public String vizdate;

	/**
	 * Constructor for the structure.
	 * @param uid The uid that has accessed this vizualization.
	 * @param name The name of the vizualization.
	 * @param user The name of a username of user who accessed this vizualization with the set uid.
	 * @param vizdate The date this uid accessed the vizualization
	 */


	VizObj(int uid, String name, String user, String vizdate){
		this.uid = uid;
		this.name = name;
		this.user = user;
		this.vizdate = vizdate;
	}//VizObj(int, String, String, String) constructor
}//VizObj class